package redisdb

import (
	"fmt"
	"sync"
	"time"

	"ser1/config"
	"ser1/utils"

	"github.com/go-redis/redis/v8"
)

var (
	client *redis.Client // Redis 客户端实例
	once   sync.Once     // 确保 Redis 客户端只初始化一次
)

// InitRedis 初始化 Redis 连接
func InitRedis() error {
	var err error
	once.Do(func() {
		// 从配置文件中读取 Redis 主机、端口和密码
		redisHost := config.GetField("REDIS_HOST")
		redisPort := config.GetField("REDIS_PORT")
		redisPassword := config.GetField("REDIS_PASSWORD")
		fmt.Println("执行redis连接")
		fmt.Println(redisHost, redisPort, redisPassword)

		// 校验配置是否为空
		if redisHost == "" || redisPort == "" {
			err = fmt.Errorf("redis 配置缺失: REDIS_HOST 或 REDIS_PORT 未设置")
			return
		}

		// 使用读取到的配置创建 Redis 客户端
		options := &redis.Options{
			Addr: fmt.Sprintf("%s:%s", redisHost, redisPort),
			DB:   0,
			// 连接池配置
			PoolSize:     250,               // 连接池大小
			MinIdleConns: 20,                // 最小空闲连接数
			MaxConnAge:   10 * time.Minute,  // 单个连接最大存活时间（到期后将被关闭）
			PoolTimeout:  30 * time.Second,  // 从连接池获取连接的超时时间
			IdleTimeout:  10 * time.Minute,  // 空闲连接的超时时间（超过该时间将被关闭）
		}

		// 如果配置了密码，则设置密码
		if redisPassword != "" {
			options.Password = redisPassword
		}

		client = redis.NewClient(options)

		// 测试 Redis 连接是否成功
		_, pingErr := client.Ping(client.Context()).Result()
		if pingErr != nil {
			err = fmt.Errorf("Redis 连接失败: %v", pingErr)
			return
		}

		fmt.Println("Redis 连接成功")
	})

	return err
}

// GetRedisClient 获取 Redis 客户端实例
func GetRedisClient() *redis.Client {
	return client
}

// SetValue 设置键值对到 Redis
func SetValue(key string, value interface{}, expiration time.Duration) error {
	err := client.Set(client.Context(), key, value, expiration).Err()
	if err != nil {
		return fmt.Errorf("设置 Redis 键值对失败: %v", err)
	}
	return nil
}

// GetValue 从 Redis 获取值
func GetValue(key string) (string, error) {
	val, err := client.Get(client.Context(), key).Result()
	if err != nil {
		if err == redis.Nil {
			return "", fmt.Errorf("Redis 键不存在: %s", key)
		}
		return "", fmt.Errorf("获取 Redis 值失败: %v", err)
	}
	return val, nil
}

// DeleteKey 从 Redis 删除键
func DeleteKey(key string) error {
	err := client.Del(client.Context(), key).Err()
	if err != nil {
		return fmt.Errorf("删除 Redis 键失败: %v", err)
	}
	return nil
}

// SelectDB 选择 Redis 数据库
func SelectDB(dbIndex int) *redis.Client {
	if client == nil {
		return nil
	}
	// 直接设置数据库索引，避免重复切换
	client.Options().DB = dbIndex
	return client
}

// Get 从 Redis 获取值
func Get(key string) (string, error) {
	if client == nil {
		return "", fmt.Errorf("redis client not initialized") // 如果客户端未初始化，返回错误
	}
	return client.Get(client.Context(), key).Result() // 获取指定键的值
}

// GetWithDB 从指定数据库的 Redis 获取值
func GetWithDB(key string, dbIndex int) (string, error) {
	if client == nil {
		return "", fmt.Errorf("redis client not initialized") // 如果客户端未初始化，返回错误
	}
	// 切换到指定的 Redis 数据库
	client.Options().DB = dbIndex
	return client.Get(client.Context(), key).Result() // 获取指定键的值
}

// Set 向 Redis 设置值
func Set(key string, value string, expiration time.Duration) error {
	if client == nil {
		return fmt.Errorf("Redis client not initialized") // 如果客户端未初始化，返回错误
	}
	return client.Set(client.Context(), key, value, expiration).Err() // 设置键值对并设置过期时间
}

// SetWithDB 向指定数据库的 Redis 设置值
func SetWithDB(key string, value string, expiration time.Duration, dbIndex int) error {
	if client == nil {
		return fmt.Errorf("Redis client not initialized") // 如果客户端未初始化，返回错误
	}
	// 切换到指定的 Redis 数据库
	client.Options().DB = dbIndex
	return client.Set(client.Context(), key, value, expiration).Err() // 设置键值对并设置过期时间
}

// SetUserTk 设置用户token到redis
func SetUserTk(uId uint, tk string, expiration time.Duration) {
	fmt.Println(tk)
	ustr := fmt.Sprintf("user_%d_tk", uId)
	err := SetWithDB(ustr, tk, expiration, 0)
	fmt.Println(err)
}

// GetUIdByTk 从redis获取用户id
func GetUIdByTk(tk string) uint {
	fmt.Println(tk)
	uId := utils.ValidateJwt(tk)
	if uId <= 0 {
		return 0
	}
	ustr := fmt.Sprintf("user_%d_tk", uId)
	tk2, _ := GetWithDB(ustr, 0)
	if tk2 != tk {
		return 0
	}
	return uint(uId)
}
